#ifndef STRUCTMESHFUNCTIONS_HPP
#define STRUCTMESHFUNCTIONS_HPP

#include "meshTypes_fwd.hpp"
#include "eigenConcat.hpp"
#include "meshEnums.hpp"

namespace hms {

Index nHorizontalEdges( Index nx, Index ny );
Index nHorizontalEdges( const Ref<const Array2i>& meshSize );


template<typename Derived>
void printAsStructMesh(
	const Eigen::DenseBase<Derived>& vals, Array2i meshSize, Index ng = 1
);

template<typename Derived, typename MeshType>
void printAsStructMesh(
	const Eigen::DenseBase<Derived>& vals, const StructMeshBase<MeshType>& mesh
);


template<typename MeshType>
Array2i parentCells(
	const StructMeshBase<MeshType>&,
	Index edge,
	Index order
);

template<typename MeshType, typename Derived>
Array2Xi parentCells(
	const StructMeshBase<MeshType>& mesh,
	const Eigen::ArrayBase<Derived>& edgeIndices,
	int order
);


template<typename MeshType>
auto whichRange( const StructMeshBase<MeshType>&, Index edge ) ->
	std::pair<EdgeRange, Index>;


bool isHorizontal( Index edgeIdx, const Ref<const Array2i>& meshSize );

BoundaryLocation whereIs( Index edge, const Ref<const Array2i>& meshSize );

BoundaryLocation whereIs(
	const BoundaryPatch& patch,
	const Ref<const Array2i>& meshSize
);

auto whereAre( 
	const Ref<const ArrayXi>& edges,
	const Ref<const Array2i>& meshSize
) -> Array<BoundaryLocation, 1, Dynamic>;

BoundaryLocation whereIsVertex( Index vert, const Array2i& meshSize);

/**
 * @brief Returns the index of the next boundary vertex.
 * 
 * @param start The starting vertex
 * @param clockwise 
 * @param meshSize 
 * @return Index 
 */
Index nextBoundaryVertex(
	Index start,
	bool clockwise,
	const Array2i& meshSize
);

template<typename MeshType>
bool validCellIndex( const StructMeshBase<MeshType>& mesh, Index cell );

template<typename MeshType>
bool validCellIndex( const StructMeshBase<MeshType>& mesh, Index i, Index j );

template<typename MeshType>
void assertValidCellIndex( const StructMeshBase<MeshType>& mesh, Index cell );

template<typename MeshType>
void assertValidCellIndex(
	const StructMeshBase<MeshType>& mesh, Index i, Index j
);


template<typename MeshType>
void addStandardBoundaryPatches( StructMeshBase<MeshType>& );

/**
 * @brief Return indices of corner vertices
 * 
 * @param meshSize mesh size in topological x- and y-direction
 * @return Array4i 
 */
Array4i structMeshCorners( const Ref<const Array2i>& meshSize );

}


#include "structMeshFunctions.tpp"

#endif
